/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
							   army.h

	$Header: /game/army.h $

	$NoKeywords: $

 ************************************************************************/

#ifndef ARMY_H_INCLUDED
#define ARMY_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <string>

#include "actor.h"
#include "adventure_path.h"
#include "cached_ptr.h"
#include "creature_array.h"
#include "ownable_event_list.h"
#include "town_type.h"
#include "scriptable_event.h"
#include "uncopyable.h"

class	t_adventure_map;
class	t_adventure_map_window;
enum	t_ai_importance;
class	t_army_mover;
enum	t_path_search_type;
class	t_player;
enum	t_player_color;
class   t_respawn_point;
enum	t_terrain_type;

// ---------------------------------------------------------------
// army which appears on the adventure map
// ---------------------------------------------------------------
class t_army : public t_actor, public t_creature_array
{
public:
	class t_events;
	friend class t_events;

	typedef t_cached_ptr< t_model > t_model_ptr;
	typedef t_army_scriptable_event t_built_in_event_id;

	enum { k_built_in_event_count = k_army_scriptable_event_count };

	t_army();
	explicit t_army( t_town_type	   boat_type ); // create as a boat
	explicit t_army( t_creature_array* creatures ); // transfers contents
	explicit t_army( t_army*		   army );		// transfers contents
	t_army( t_creature_type					creature_type,
			int								creature_count,
			int								initial_growing_experience_value,
			int								initial_max_growth_per_day,
			int								initial_non_growing_experience_value,
			t_patrol_type					patrol_type,
			t_uint8							patrol_radius,
			t_adv_map_point					initial_location ); // For respawns

	virtual ~t_army();

	virtual void				activate_trigger( t_army* army, t_adv_map_point const& point, 
												  t_direction direction, 
												  t_adventure_frame* frame );
	void						touch_armies( t_army*				 army, 
											  t_adv_map_point const& point, 
											  t_direction			 direction, 
											  t_adventure_frame*	 frame, 
											  t_adv_map_point const& return_point );
	int							ai_get_wander_direction() const;
	void						ai_set_wander_direction(int direction);
	float						ai_value() const;
	virtual float				ai_value( t_adventure_ai const& ai, t_creature_array const& army, int move_cost ) const;
	virtual bool				blocks_army( t_creature_array const&			army,
											 t_path_search_type 	path_type ) const;
	virtual bool				can_be_hidden() const;
	virtual void				change_movement( int amount );
	virtual void				destroy();
	void						execute_script( t_army_scriptable_event event, 
												t_army* opposing_army);
	virtual void				expend_all_movement();
	void						expend_embarkation_movement();
	virtual void				expend_most_movement( int max_remaining_movement );
	virtual t_bitmap_cursor const& get_cursor( t_adventure_map_window const& window,
											   t_army const* army ) const;
	virtual t_skill_mastery		get_anti_stealth_level() const;
	t_army*						get_army();
	t_army const*				get_army() const;
	virtual int					get_attack_range() const;
	virtual t_town_type			get_boat_type () const;
	t_creature_array&			get_creatures();
	t_creature_array const& 	get_creatures() const;
	t_adv_map_point const&		get_destination() const;
	virtual t_footprint const & get_footprint() const;
	virtual t_icon_type			get_icon_type() const;
	t_ai_importance				get_importance() const;	
	virtual t_model const & 	get_model() const;
	virtual std::string 		get_name() const;
	int 						get_next_step_cost() const;
	t_player_color				get_owner_color() const;
	virtual int					get_owner_number() const;
	t_adventure_path const& 	get_path() const;
	virtual t_player_color		get_player_color() const;
	t_respawn_point				get_respawn_data() const;
	virtual int 				get_scouting_range() const;
	bool						get_sleeping() const;
	virtual int 				get_subimage_depth_offset( int subimage_num ) const;
	virtual int 				get_version() const;
	virtual void				initialize( t_adventure_map& map );
	virtual bool				is_boat() const;
	virtual bool				is_graveyard() const;
	virtual bool				is_removable() const;
	virtual bool				is_triggered_by( t_creature_array const& army ) const;
	void						leave_boat( t_level_map_point_2d const& point );
	using t_actor::move; // Hoist move() from the base class so our move() won't hide it
	void						move( t_level_map_point_2d const& point );
	virtual void				on_begin_turn();
	virtual void				on_combat_end( t_army* attacker, t_combat_result result, 
										       t_creature_array* losses, 
											   t_adventure_frame* adventure_frame );
	virtual void				on_end_turn();
	virtual void				place( t_adventure_map& map, t_adv_map_point const& point );
	virtual bool				preplacement( t_adventure_map& map, int pass );
	virtual bool				process_continuous_events( t_adventure_map& map );
	virtual void				process_new_day();
	virtual bool				process_timed_events( t_adventure_map& map, bool start_of_day = true );
	virtual bool				process_triggerable_events( t_adventure_map& map, std::string const& name );
	bool						read( std::streambuf& buffer, int version );
	virtual bool				read_from_map( std::streambuf& buffer, t_progress_handler* handler );
	virtual void				read_postplacement( t_adventure_map& map );
	virtual void				right_click( t_mouse_event const& event,
											 t_adventure_frame* adventure_frame );
	virtual bool				select();
	void						set_boat_type( t_town_type boat_type );
	virtual void				set_in_combat( bool arg );
	void						set_owner( int arg );
	void						set_path( t_adventure_path const& path );
	void						set_sleeping( bool is_asleep = true );
	virtual bool				subimage_is_underlay( int subimage_num ) const;
	void						take_army( t_army & source ); 
	void						take_events( t_events & new_events );
	void						trigger_events();
	virtual bool				trigger_event(t_army& army);
	void						teleport( t_adv_map_point const & new_point);
	virtual void				update_state();
	virtual bool				is_visible_to( int team_num ) const;
	virtual bool				write_object( std::streambuf& buffer ) const;

protected:
	typedef t_ownable_built_in_event			t_built_in_event;
	typedef t_ownable_built_in_event_ptr		t_built_in_event_ptr;
	typedef t_ownable_timed_event				t_timed_event;
	typedef t_ownable_timed_event_ptr			t_timed_event_ptr;
	typedef t_ownable_timed_event_list			t_timed_event_list;
	typedef t_ownable_triggerable_event 		t_triggerable_event;
	typedef t_ownable_triggerable_event_ptr 	t_triggerable_event_ptr;
	typedef t_ownable_triggerable_event_list	t_triggerable_event_list;
	typedef t_ownable_continuous_event			t_continuous_event;
	typedef t_ownable_continuous_event_ptr		t_continuous_event_ptr;
	typedef t_ownable_continuous_event_list 	t_continuous_event_list;

	void	add_to_owner_army_list();
	void	add_to_owner_graveyard_list();
	void	add_to_owner_lists();
	void	add_to_owner_object_list();
	void	compute_initial_alignment_and_xp();
	int		compute_scouting_range() const;
	void	do_charm( t_army* army, t_adventure_frame* frame );
	void	init();
	void	remove_from_owner_army_list();
	void	remove_from_owner_graveyard_list();
	void	remove_from_owner_lists();
	void	remove_from_owner_object_list();
	void	update_frame();
	void	update_scouting_range();

	bool						m_add_starting_troops; // temporary used during map reading.
	t_ai_importance				m_ai_importance;
	int							m_ai_wander_direction;
	t_town_type 				m_boat_type;
	t_built_in_event_ptr		m_built_in_events[ k_built_in_event_count ];
	t_continuous_event_list		m_continuous_events;
	bool						m_in_combat;
	t_town_type					m_initial_alignment; // For wandering monsters: Alignment of most powerful creature from the map editor
	int							m_initial_growing_experience_value; // For wandering monsters: XP value that will grow over time
	int							m_initial_max_growth_per_day; // For wandering monsters: maximum xp growth of creatures per day 
	int					 		m_initial_non_growing_experience_value; // For wandering monsters: XP value that will NOT grow over time
	bool						m_is_graveyard : 1;
	bool						m_on_owner_army_list : 1;
	bool						m_on_owner_graveyard_list : 1;
	bool						m_on_owner_object_list : 1;
	t_model_ptr 				m_model_ptr;
	int 						m_owner;
	t_adventure_path			m_path;
	t_adv_map_point 			m_path_destination;
	int 						m_path_start_cost;
	t_player_color				m_player_color;
	int 						m_scouting_range;
	bool						m_sleeping;
	t_timed_event_list			m_timed_events;
	t_adv_map_point				m_trigger_events_position; // Current or last position when trigger_events() was called
	t_triggerable_event_list	m_triggerable_events;

private:
	bool read_built_in_events( std::streambuf & stream, int version, int script_version );
	bool write_built_in_events( std::streambuf & stream ) const;
};

inline float t_army::ai_value() const
{
	return t_creature_array::ai_value();
}

inline 	t_town_type t_army::get_boat_type () const
{
	return m_boat_type;
}

inline t_creature_array& t_army::get_creatures()
{
	return *this;
}

inline t_creature_array const& t_army::get_creatures() const
{
	return *this;
}

inline t_adv_map_point const& t_army::get_destination() const
{
	return m_path_destination;
}

inline t_adventure_path const& t_army::get_path() const
{
	return m_path;
}

inline bool t_army::get_sleeping() const
{
	return m_sleeping;
}

inline t_ai_importance t_army::get_importance() const
{
	return m_ai_importance;
}

inline void t_army::set_boat_type( t_town_type boat_type )
{
	m_boat_type = boat_type;
}

inline void	t_army::set_sleeping( bool is_asleep )
{
	m_sleeping = is_asleep;
}

inline 	void t_army::teleport( t_adv_map_point const & new_point)
{
	t_actor::move( new_point );
}

int get_terrain_cost( t_terrain_type terrain );

// ---------------------------------------------------------------
// t_army::t_events class
// ---------------------------------------------------------------

class t_army::t_events : public t_uncopyable
{
public:
	// Constructor
	t_events();

	// Member functions
	bool	read_from_map( std::streambuf & stream, int format_version );

private:
	// Data members
	t_built_in_event_ptr		m_built_in_events[ k_built_in_event_count ];
	t_continuous_event_list 	m_continuous_events;
	t_timed_event_list			m_timed_events;
	t_triggerable_event_list	m_triggerable_events;

	// Member functions
	bool read_built_in_events_from_map( std::streambuf & stream, int version );

	friend class t_army;
};


// ---------------------------------------------------------------
// merge two creature arrays
// ---------------------------------------------------------------
void merge( t_creature_array& destination, t_creature_array& source );


#endif // ARMY_H_INCLUDED
